﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Carbon.Web.Forms.jQueryForms
{
    public interface IDropDownListItemCollection : IListEditorItemCollection
    {
        int? SelectedIndex { get; set; }
        bool CanSelectNull { get; }
        Object SelectedItem { get; }
    }

    [Serializable]
    public class DropDownListItemCollection<T, TKey> : ListEditorItemCollection<T>, IDropDownListItemCollection
    {
        public override object Clone()
        {
            DropDownListItemCollection<T, TKey> collection = new DropDownListItemCollection<T, TKey>(EmptyArray<T>.Instance, IdGenerator, NameGenerator, default(TKey), CanSelectNull);
            CloneDropDownListItemCollectionProperties(collection);
            return collection;
        }

        protected void CloneDropDownListItemCollectionProperties(DropDownListItemCollection<T, TKey> collection)
        {
            base.CloneListEditorItemCollectionProperties(collection);
            collection.SelectedIndex = this.SelectedIndex;
            collection.CanSelectNull = this.CanSelectNull;
            collection.m_IdGenerator = this.m_IdGenerator;
        }

        private int? m_SelectedIndex = default(int?);
        public int? SelectedIndex
        {
            get
            {
                return m_SelectedIndex;
            }
            set
            {
                m_SelectedIndex = value;
                int i = 0;
                foreach (ListEditorItem<T> item in this)
                {
                    item.Selected = value.HasValue && i == value.Value;
                    ++i;
                }
            }
        }

        public TKey SelectedKey
        {
            get
            {
                ListEditorItem<T> item = this.Where(i => i.Selected).SingleOrDefault();
                if (item == null)
                    return default(TKey);

                return IdGenerator(item.Model);
            }
            set
            {
                int? selectedIndex = null;
                int i = 0;
                foreach (ListEditorItem<T> item in this)
                {
                    TKey key = IdGenerator(item.Model);

                    bool isSelected = value != null && value.Equals(key);

                    if (isSelected)
                    {
                        if (selectedIndex != null)
                            throw new InvalidOperationException("Two items have same index.");

                        selectedIndex = i;
                    }

                    item.Selected = isSelected;
                    ++i;
                }

                this.SelectedIndex = selectedIndex;
            }
        }

        private bool m_CanSelectNone = default(bool);
        public bool CanSelectNull
        {
            get
            {
                return m_CanSelectNone;
            }
            set
            {
                m_CanSelectNone = value;
            }
        }

        virtual public T SelectedItem
        {
            get
            {
                if (SelectedIndex == null)
                {
                    return default(T);
                }
                else
                {
                    return this[SelectedIndex.Value].Model;
                }
            }
            set
            {
                if (value == null)
                {
                    SelectedIndex = null;
                }
                else
                {
                    this.SelectedIndex = null;
                    for (int i = 0; i < this.Count; ++i)
                    {
                        if (EqualityComparer<T>.Default.Equals(this[i].Model, value))
                        {
                            this.SelectedIndex = i;
                            break;
                        }
                    }

                    if (this.SelectedIndex == null)
                        throw new InvalidOperationException("Object not found in collection.");
                }
            }
        }

        Object IDropDownListItemCollection.SelectedItem
        {
            get
            {
                return this.SelectedItem;
            }
        }

        private Func<T, TKey> m_IdGenerator = default(Func<T, TKey>);
        public Func<T, TKey> IdGenerator
        {
            get
            {
                return m_IdGenerator;
            }
        }

        public DropDownListItemCollection(IEnumerable<T> collection, Func<T, TKey> idGenerator, Func<T, string> nameGenerator, TKey id, bool canSelectNull)
            : base(collection.Select(i => new ListEditorItem<T>() { Model = i, Selected = false }), nameGenerator)
        {
            if (idGenerator == null) throw new NullReferenceException("idGenerator");

            this.m_IdGenerator = idGenerator;

            this.m_CanSelectNone = canSelectNull;

            this.SelectedKey = id;
        }
    }
}
